#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <atomic> //c++11中引入的原子性计数
#include <sys/stat.h>
#include <fstream>
#include <unistd.h>
#include <sys/time.h>
#include <boost/algorithm/string.hpp>

// 存放时间、路径、文件、字符串切分工具
namespace ns_util
{
    const std::string temp_path = "./temp/";

    class TimeUtil
    {
    public:
        static std::string GetTimeStamp()
        {
            struct timeval _time;
            gettimeofday(&_time, nullptr);
            return std::to_string(_time.tv_sec);
        }

        // 获得毫秒时间戳
        static std::string GetTimeMs()
        {
            struct timeval _time;
            gettimeofday(&_time, nullptr);
            return std::to_string(_time.tv_sec * 1000 + _time.tv_usec / 1000);
        }
    };

    class PathUtil
    {
    public:
        static std::string AddSuffix(const std::string &file_name, const std::string &suffix)
        {
            std::string path_name = temp_path;
            path_name += file_name;
            path_name += suffix;
            return path_name;
        }
        // 编译时需要有的临时文件
        //  构建源文件路径+后缀的完整文件名
        //  1234 -> ./temp/1234.cpp
        static std::string Src(const std::string &file_name)
        {
            return AddSuffix(file_name, ".cpp");
        }
        // 构建可执行程序的完整路径+后缀名
        static std::string Exe(const std::string &file_name)
        {
            return AddSuffix(file_name, ".exe");
        }

        static std::string CompilerError(const std::string &file_name)
        {
            return AddSuffix(file_name, ".compile_error");
        }

        // 运行时需要的临时文件
        static std::string Stdin(const std::string &file_name)
        {
            return AddSuffix(file_name, ".stdin");
        }
        static std::string Stdout(const std::string &file_name)
        {
            return AddSuffix(file_name, ".stdout");
        }
        // 构建该程序对应的标准错误完整的路径+后缀名
        static std::string Stderr(const std::string &file_name)
        {
            return AddSuffix(file_name, ".stderr");
        }
    };

    class FileUtil
    {
    public:
        static bool IsFileExists(const std::string &path_name)
        {
// stat 函数：
// stat 是一个 POSIX 系统调用，用于获取文件的元数据信息（例如大小、权限等）。
// 它的第一个参数是文件的路径名，第二个参数是一个 struct stat 结构，用于存储文件的属性信息。
// 如果调用成功，stat 返回 0，表示文件存在且获取文件信息成功。
// 如果文件不存在或者路径无效，stat 返回 -1，并设置 errno 来指示具体的错误原因（如文件未找到）。
// path_name.c_str()：
// path_name 是传入的文件路径，类型为 std::string。
// c_str() 将 std::string 转换为 C 风格的字符串，以便传递给 stat 函数，因为 stat 需要 const char* 类型的参数。
// 返回值：
// 如果 stat 成功，文件存在，返回 true。
// 如果 stat 失败，文件不存在，返回 false。

            struct stat st;
            if (stat(path_name.c_str(), &st) == 0)
            {
                // 获取属性成功，文件已经存在
                return true;
            }

            return false;
        }

        static std::string UniqFileName()
        {
            static std::atomic_uint id(0);
            id++;
            // 毫秒级时间戳+原子性递增唯一值: 来保证唯一性
            std::string ms = TimeUtil::GetTimeMs();
            std::string uniq_id = std::to_string(id);
            return ms + "_" + uniq_id;
        }

//  1. 追踪系统行为
// 时间戳帮助记录项目中的关键操作发生的时间。例如，项目中涉及题目加载、主机上线/离线、负载均衡、用户请求处理等一系列操作，时间戳可以记录这些操作发生的顺序和时长。这样，当系统出现异常或性能问题时，您可以通过日志中的时间戳精确定位问题发生的时刻和过程。

// 2. 分析负载变化
// 项目中实现了负载均衡功能。通过时间戳，您可以监控各台主机在不同时刻的负载变化，了解系统的压力峰值和瓶颈。例如，记录主机负载的增加和减少操作时，通过时间戳可以分析在某个时间段内是否有负载不均衡或负载过重的情况。

// 3. 调试与优化
// 当系统处理用户请求（如提交代码、获取题目）时，时间戳帮助记录每个请求处理的时间。这有助于在项目调试和优化过程中，衡量每个功能模块的执行时间。比如，如果某个请求处理过慢，通过时间戳可以精确判断是哪一步骤耗费了过多时间，从而优化性能。

// 4. 监控服务状态
// 在您的项目中，负载均衡器需要监控编译服务主机的在线和离线状态。时间戳可以记录主机何时上线或离线，帮助分析主机状态变动的频率和原因，及时发现问题并进行维护。

// 5. 并发处理分析
// 在并发处理编译任务时，时间戳可以帮助分析多个任务的处理顺序，避免任务之间的相互影响或竞争条件。通过时间戳记录不同任务的开始和结束时间，可以确保系统的多任务调度顺利进行。




        static bool WriteFile(const std::string &target, const std::string &content)
        {
            // ToDo
            std::ofstream out(target);
            if (!out.is_open())
            {
                return false;
            }
            out.write(content.c_str(), content.size());
            out.close();
            return true;
        }

        static bool ReadFile(const std::string &target, std::string *content, bool keep = false)
        {
            // ToDo
            (*content).clear();

            std::ifstream in(target);
            if (!in.is_open())
            {
                return false;
            }
            std::string line;
            // getline:不保存行分割符,有些时候需要保留\n,
            // getline内部重载了强制类型转化
            while (std::getline(in, line))
            {
                (*content) += line;
                (*content) += (keep ? "\n" : "");
            }
            in.close();
            return true;
        }
    };

    class StringUtil
    {
    public:
        /*************************************
         * str: 输入型，目标要切分的字符串
         * target: 输出型，保存切分完毕的结果
         * sep: 指定的分割符
         * **********************************/
        static void SplitString(const std::string &str, std::vector<std::string> *target, const std::string &sep)
        {
            // boost split
            boost::split((*target), str, boost::is_any_of(sep), boost::algorithm::token_compress_on);
        }
    };

}